home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 2007 December / PCWKCD1207B.iso / Blogowanie poza sfera / Flock 0.9.1.3 stable / flock-0.9.1.3.en-US.win32.exe / flock / components / flockIndexer.js < prev    next >
Text File  |  2007-10-12  |  22KB  |  673 lines

  1. //
  2. // BEGIN FLOCK GPL
  3. // 
  4. // Copyright Flock Inc. 2005-2007
  5. // http://flock.com
  6. // 
  7. // This file may be used under the terms of of the
  8. // GNU General Public License Version 2 or later (the "GPL"),
  9. // http://www.gnu.org/licenses/gpl.html
  10. // 
  11. // Software distributed under the License is distributed on an "AS IS" basis,
  12. // WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  13. // for the specific language governing rights and limitations under the
  14. // License.
  15. // 
  16. // END FLOCK GPL
  17. //
  18.  
  19. const CLASS_ID                = Components.ID("{C2BFF231-7A51-4764-8409-A1B22B2F5147}");
  20. const CLASS_NAME              = "Flock Indexer";
  21. const CONTRACT_ID             = "@flock.com/indexer;1";
  22.  
  23. const FLOCK_NS = "http://flock.com/rdf#";
  24. const NSCP_NS = "http://home.netscape.com/NC-rdf#";
  25.  
  26. const PROP_URL   = NSCP_NS + "URL";
  27. const PROP_NAME  = NSCP_NS + "Name";
  28. const PROP_CHILD = NSCP_NS + "child";
  29.  
  30. const Cc = Components.classes;
  31. const Ci = Components.interfaces;
  32. const Cr = Components.results;
  33.  
  34. /* from nspr's prio.h */
  35. const PR_RDONLY      = 0x01;
  36. const PR_WRONLY      = 0x02;
  37. const PR_RDWR        = 0x04;
  38. const PR_CREATE_FILE = 0x08;
  39. const PR_APPEND      = 0x10;
  40. const PR_TRUNCATE    = 0x20;
  41. const PR_SYNC        = 0x40;
  42. const PR_EXCL        = 0x80;
  43.  
  44. const OP_DELETE      = 0;
  45. const OP_ADD_FLOCK   = 1;
  46. const OP_ADD_HISTORY = 2;
  47.  
  48. function flockIndexer() {
  49.   var obs = Cc["@mozilla.org/observer-service;1"].getService(Ci.nsIObserverService);
  50.   obs.addObserver(this, "xpcom-shutdown", false);
  51. }
  52.  
  53. flockIndexer.prototype = {
  54.  
  55.   init: function INDEXER_init() {
  56.     this._enabled = false;
  57.     this._enabledWebHistory = false;
  58.     
  59.     this._logger = Cc["@flock.com/logger;1"].createInstance(Ci.flockILogger);
  60.     this._logger.init("indexer");
  61.     
  62.     this._logger.info("starting up...");
  63.     
  64.     this._RDFS = Cc["@mozilla.org/rdf/rdf-service;1"]
  65.       .getService(Ci.nsIRDFService);
  66.     this._resURL = this._RDFS.GetResource(PROP_URL);
  67.     this._resName = this._RDFS.GetResource(PROP_NAME);
  68.     this._resHistoryRoot = this._RDFS.GetResource("NC:HistoryRoot");
  69.     this._resHistoryChild = this._RDFS.GetResource(PROP_CHILD);
  70.     this._resIsIndexable = this._RDFS.GetResource(FLOCK_NS + "isIndexable");
  71.     this._resTitle = this._RDFS.GetResource(NSCP_NS + "Name");
  72.     this._resDescription = this._RDFS.GetResource(NSCP_NS + "Description");
  73.     this._resTags = this._RDFS.GetResource(FLOCK_NS + "tags");
  74.  
  75.     this._searchService = Cc["@flock.com/lucene/flockLucene;1"]
  76.       .getService(Ci.flockILucene);
  77.     this._favService = Cc["@mozilla.org/rdf/datasource;1?name=flock-favorites"]
  78.       .getService(Ci.flockIRDFObservable);
  79.     this._historyRdf = Cc["@mozilla.org/rdf/datasource;1?name=history"]
  80.       .getService(Ci.nsIRDFDataSource);
  81.     this._ios = Cc["@mozilla.org/network/io-service;1"]
  82.       .getService(Ci.nsIIOService);
  83.  
  84.     this._coop = Cc["@flock.com/singleton;1"].getService(Ci.flockISingleton)
  85.       .getSingleton("chrome://browser/content/flock/common/load-faves-coop.js")
  86.       .wrappedJSObject;
  87.  
  88.     var dirService = Cc["@mozilla.org/file/directory_service;1"]
  89.       .getService(Ci.nsIProperties);
  90.     var profileDir = dirService.get("ProfD", Ci.nsIFile);
  91.  
  92.     // Clean up old cardinal index dir
  93.     var oldHistorySearchDir = profileDir.clone();
  94.     oldHistorySearchDir.append("historysearch");
  95.     try {
  96.       oldHistorySearchDir.remove(true);
  97.     }
  98.     catch (ex) {
  99.     }
  100.  
  101.     // initialize Lucene
  102.     var luceneDir = profileDir.clone();
  103.     luceneDir.append("lucene");
  104.     this._searchService.init(luceneDir);
  105.  
  106.     // initialize the queue
  107.     this._initQueue();
  108.  
  109.     // init queue processing timer
  110.     this._timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
  111.     
  112.     // init page text store
  113.     this._pageText = {};
  114.     
  115.     // create tokenizer
  116.     this._tokenizer = Cc["@flock.com/tokenizer;1"].createInstance(Ci.flockITokenizer);
  117.     
  118.     // init with current prefs
  119.     this.observe(null, "nsPref:changed", null);
  120.     
  121.     // watch for pref changes
  122.     var prefService = Cc["@mozilla.org/preferences-service;1"]
  123.       .getService(Ci.nsIPrefBranch2);
  124.     prefService.addObserver("flock.service.indexer.enabled", this, false);
  125.     prefService.addObserver("flock.service.indexer.indexWebHistory", this, false);
  126.   },
  127.   
  128.   rebuildIndex: function INDEXER_rebuildIndex() {
  129.     this._logger.info("rebuilding index...");
  130.  
  131.     // reindex history
  132.     var records = this._historyRdf.GetTargets(this._resHistoryRoot,
  133.                                               this._resHistoryChild,
  134.                                               true);
  135.     var record, url;
  136.     while (records.hasMoreElements()) {
  137.       record = records.getNext().QueryInterface(Ci.nsIRDFResource);
  138.       try {
  139.         url = this._ios.newURI(record.ValueUTF8, null, null);
  140.       } catch (e) {
  141.         url = null;
  142.       }
  143.       if (url && url.scheme == "http") {
  144.         this._addOp(OP_ADD_HISTORY, "history:" + url.spec);
  145.       }
  146.     }
  147.   },
  148.   
  149.   _getQueueFile: function INDEXER__getQueueFile() {
  150.     var file = Cc["@mozilla.org/file/directory_service;1"]
  151.       .getService(Ci.nsIProperties).get("ProfD", Ci.nsILocalFile);
  152.     file.append("indexerQueue.js");
  153.     return file;
  154.   },
  155.   
  156.   _initQueue: function INDEXER__initQueue() {
  157.     var queue;
  158.  
  159.     try {
  160.       var file = this._getQueueFile();
  161.  
  162.       var stream = Cc["@mozilla.org/network/file-input-stream;1"]
  163.         .createInstance(Ci.nsIFileInputStream);
  164.       stream.init(file, PR_RDONLY, 0, 0);
  165.  
  166.       var cvstream = Cc["@mozilla.org/intl/converter-input-stream;1"]
  167.         .createInstance(Ci.nsIConverterInputStream);
  168.       cvstream.init(stream, "UTF-8", 1024,
  169.                     Ci.nsIConverterInputStream.DEFAULT_REPLACEMENT_CHARACTER);
  170.  
  171.       var content = "";
  172.       var data = {};
  173.       while (cvstream.readString(4096, data)) {
  174.         content += data.value;
  175.       }
  176.       cvstream.close();
  177.  
  178.       queue = content.replace(/\r\n?/g, "\n");
  179.       file.remove(false);
  180.     } catch (e) {
  181.       queue = null;
  182.     }
  183.  
  184.     if (queue) {
  185.       try {
  186.         var s = new Components.utils.Sandbox("about:blank");
  187.         this._queue = Components.utils.evalInSandbox(queue, s);
  188.         this._logger.info("restored queue");
  189.         return;
  190.       } catch (e) {
  191.         this._logger.error("unable to restore queue");
  192.       }
  193.     }
  194.     
  195.     // default to empty queue
  196.     this._queue = [];
  197.   },
  198.   
  199.   _saveQueue: function INDEXER__saveQueue() {
  200.     // do nothing if queue is empty
  201.     if (this._queue.length == 0)
  202.       return;
  203.     
  204.     try {
  205.       this._logger.info("saving queue...");
  206.       var file = this._getQueueFile();
  207.  
  208.       var ostream = Cc["@mozilla.org/network/safe-file-output-stream;1"]
  209.         .createInstance(Ci.nsIFileOutputStream);
  210.       ostream.init(file, PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE, 0600, 0);
  211.  
  212.       var converter = Cc["@mozilla.org/intl/scriptableunicodeconverter"]
  213.         .createInstance(Ci.nsIScriptableUnicodeConverter);
  214.       converter.charset = "UTF-8";
  215.  
  216.       var data = this._queue.toSource();
  217.       var convdata = converter.ConvertFromUnicode(data) + converter.Finish();
  218.  
  219.       ostream.write(convdata, convdata.length);
  220.  
  221.       if (ostream instanceof Ci.nsISafeOutputStream) {
  222.         ostream.finish();
  223.       } else {
  224.         ostream.close();
  225.       }
  226.     } catch (e) {
  227.       this._logger.error("unable to save queue");
  228.     }
  229.   },
  230.   
  231.   _enable: function INDEXER__enable() {
  232.     if (!this._enabled) {
  233.       // start watching the favorites and history graphs
  234.       this._favService.addArcObserver(Ci.flockIRDFObserver.TYPE_ALL, null,
  235.                                       this._resIsIndexable, null, this);
  236.       this._favService.addArcObserver(Ci.flockIRDFObserver.TYPE_CHANGE, null,
  237.                                       this._resTitle, null, this);
  238.       this._favService.addArcObserver(Ci.flockIRDFObserver.TYPE_CHANGE, null,
  239.                                       this._resDescription, null, this);
  240.       this._favService.addArcObserver(Ci.flockIRDFObserver.TYPE_CHANGE, null,
  241.                                       this._resTags, null, this);
  242.       this._historyRdf.AddObserver(this);
  243.       this._enabled = true;
  244.       this._enabledWebHistory = true;
  245.       this._logger.info("indexing enabled");
  246.     }
  247.   },
  248.   
  249.   _disable: function INDEXER__disable() {
  250.     if (this._enabled) {
  251.       // stop watching the favorites and history graphs
  252.       this._favService.removeArcObserver(Ci.flockIRDFObserver.TYPE_ALL, null,
  253.                                          this._resIsIndexable, null, this);
  254.       this._favService.removeArcObserver(Ci.flockIRDFObserver.TYPE_CHANGE, null,
  255.                                       this._resTitle, null, this);
  256.       this._favService.removeArcObserver(Ci.flockIRDFObserver.TYPE_CHANGE, null,
  257.                                       this._resDescription, null, this);
  258.       this._favService.removeArcObserver(Ci.flockIRDFObserver.TYPE_CHANGE, null,
  259.                                       this._resTags, null, this);
  260.       this._historyRdf.RemoveObserver(this);
  261.       this._enabled = false;
  262.       this._enabledWebHistory = false;
  263.       this._logger.info("indexing disabled");
  264.     }
  265.   },
  266.  
  267.   _enableWebHistory: function INDEXER__enableWebHistory() {
  268.     if (this._enabled) {
  269.       if (!this._enabledWebHistory) {
  270.         this._historyRdf.AddObserver(this);
  271.         this._enabledWebHistory = true;
  272.         this._logger.info("web history indexing enabled");
  273.       }
  274.     }
  275.   },
  276.   
  277.   _disableWebHistory: function INDEXER__disableWebHistory() {
  278.     if (this._enabled) {
  279.       if (this._enabledWebHistory) {
  280.         this._historyRdf.RemoveObserver(this);
  281.         this._enabledWebHistory = false;
  282.         this._logger.info("web history indexing disabled");
  283.       }
  284.     }
  285.   },
  286.   
  287.   _shutdown: function INDEXER__shutdown() {
  288.     this._disable();
  289.     this._timer.cancel();
  290.     this._saveQueue();
  291.     this._logger.info("shut down");
  292.   },
  293.   
  294.   _processQueue: function INDEXER__processQueue(sync) {
  295.     var batchSize = 1;
  296.     var c = 0;
  297.     while (this._queue.length > 0 && c < batchSize) {
  298.       c++;
  299.       var op = this._queue[0];
  300.       var instruction = op[0];
  301.       var uri = op[1];
  302.       switch (instruction) {
  303.         case OP_DELETE:
  304.           this._logger.info("removing " + uri);
  305.           if (sync) {
  306.             this._searchService.deleteDocumentSync(uri);
  307.           } else {
  308.             this._searchService.deleteDocument(uri, this);
  309.           }
  310.           break;
  311.  
  312.         case OP_ADD_FLOCK:
  313.           var obj = this._coop.get(uri);
  314.           if (!obj) {
  315.             var msg = "trying to add nonexistent object: " + uri;
  316.             this._logger.error(msg);
  317.             throw Components.Exception(msg, Cr.NS_ERROR_UNEXPECTED);
  318.           }
  319.  
  320.           var url = obj.URL;
  321.           if (!url) {
  322.              this._logger.warn("unable to get URL for " + uri);
  323.              url = "";
  324.           }
  325.  
  326.           var type = obj.flockType;
  327.           var title = obj.name;
  328.           if (obj.tags) {
  329.             var tags = obj.tags;
  330.           } else {
  331.             var tags = "";
  332.           }
  333.           if (obj.description) {
  334.             var description = obj.description;
  335.           } else {
  336.             var description = "";
  337.           }
  338.           var text = "";
  339.           this._logger.info("indexing " + uri + " type: " + type + " title: " + title + " url: " + url);
  340.  
  341.           if (sync) {
  342.             this._searchService.addDocumentSync(uri, type, url, title, tags, description, text);
  343.           } else {
  344.             this._searchService.addDocument(uri, type, url, title, tags, description, text, this);
  345.           }
  346.           break;
  347.  
  348.         case OP_ADD_HISTORY:
  349.           this._logger.info("indexing " + uri + " type: history");
  350.           if (!sync) {
  351.             this._addHistoryDocument(uri);
  352.           }
  353.           break;
  354.       }
  355.     }
  356.   },
  357.   
  358.   _addHistoryDocument: function INDEXER__addHistoryDocument(aURI) {
  359.     var uri = aURI;
  360.     var url = uri.substr("history:".length);
  361.     var title = "";
  362.     var tags = "";
  363.     var description = "";
  364.     var data = "";
  365.     
  366.     var resource = this._historyRdf.GetSource(this._resURL,
  367.                                               this._RDFS.GetResource(url),
  368.                                               true);
  369.     if (resource) {
  370.       var title_node = this._historyRdf.GetTarget(resource, this._resName, true);
  371.       if (title_node && title_node.QueryInterface(Ci.nsIRDFLiteral)) {
  372.         title = title_node.Value;
  373.         this._logger.debug("got title");
  374.       }
  375.     }
  376.     if (url in this._pageText) {
  377.       data = this._pageText[url];
  378.       delete this._pageText[url];
  379.     }
  380.     this._searchService.addDocument(uri, "history", url, title, tags, description, data, this);
  381.     this._logger.debug("document indexed text: " + data);
  382.   },
  383.   
  384.   _addOp: function INDEXER__addOp(aOp, aURI) {
  385.     this._queue.push([aOp, aURI]);
  386.     this._logger.info("queued operation op: " + aOp + " uri: " + aURI);
  387.     this._timer.initWithCallback(this, 250, Ci.nsITimer.TYPE_ONE_SHOT);
  388.   },
  389.   
  390.   _retireOp: function INDEXER__retireOp() {
  391.     this._queue.shift();
  392.     if (this._queue.length > 0) {
  393.       this._timer.initWithCallback(this, 0, Ci.nsITimer.TYPE_ONE_SHOT);
  394.     }
  395.   },
  396.   
  397.   _handlePageLoad: function INDEXER_handlePageLoad(document) {
  398.     var url = document.documentURI;
  399.     this._logger.debug("_handlePageLoad: " + url);
  400.     this._pageText[url] = this._tokenizer.tokenizeDOMNode(document, document.body);
  401.     this._addOp(OP_ADD_HISTORY, "history:" + url);
  402.   },
  403.   
  404.   // nsIDOMEventListener
  405.   handleEvent: function INDEXER_handleEvent(aEvent) {
  406.     switch(aEvent.type) {
  407.       case "load":
  408.         var url;
  409.         try {
  410.           url = this._ios.newURI(aEvent.originalTarget.documentURI, null, null);
  411.         } catch (e) { }
  412.         if (url && url.scheme == "http") {
  413.           this._handlePageLoad(aEvent.originalTarget);
  414.         }
  415.         break;
  416.     }
  417.   },
  418.  
  419.   // flockIMigratable
  420.   get shortname() { return 'Indexer'; },
  421.   
  422.   // flockIMigratable
  423.   needsMigration: function INDEXER_needsMigration(oldVersion) {
  424.     return oldVersion.substr(0, 3) == "0.7";
  425.   },
  426.   
  427.   // flockIMigratable
  428.   startMigration: function INDEXER_startMigration(oldVersion, listener) {
  429.     return null;
  430.   },
  431.   
  432.   // flockIMigratable
  433.   finishMigration: function INDEXER_finishMigration(ctxtWrapper) {
  434.   },
  435.   
  436.   // flockIMigratable
  437.   doMigrationWork: function INDEXER_doMigrationWork(ctxtWrapper) {
  438.     this.rebuildIndex();
  439.     return false;
  440.   },
  441.   
  442.   // flockILuceneListener
  443.   onAddDocumentComplete: function INDEXER_onAddDocumentComplete(aURI) {
  444.     this._logger.debug("onAddDocumentComplete: " + aURI);
  445.     this._retireOp();
  446.   },
  447.  
  448.   // flockILuceneListener
  449.   onDeleteDocumentComplete: function INDEXER_onDeleteDocumentComplete(aURI) {
  450.     this._logger.debug("onDeleteDocumentComplete: " + aURI);
  451.     this._retireOp();
  452.   },
  453.  
  454.   // nsITimerCallback
  455.   notify: function INDEXER_notify(timer) {
  456.     this._processQueue(false);
  457.   },
  458.  
  459.   // flockIRDFObserver
  460.   rdfChanged: function INDEXER__rdfChanged(ds, type, rsrc, pred, obj, oldObj) {
  461.     if (pred == this._resIsIndexable) {
  462.       switch (type) {
  463.         case Ci.flockIRDFObserver.TYPE_ASSERT:
  464.           var indexable = this._coop.get_from_resource(rsrc);
  465.           if (indexable.isIndexable) {
  466.             this._addOp(OP_ADD_FLOCK, indexable.id());
  467.           }
  468.           break;
  469.   
  470.         case Ci.flockIRDFObserver.TYPE_CHANGE:
  471.           var indexable = this._coop.get_from_resource(rsrc);
  472.           var op = indexable.isIndexable ? OP_ADD_FLOCK : OP_DELETE;
  473.           this._addOp(op, indexable.id());
  474.           break;
  475.   
  476.         case Ci.flockIRDFObserver.TYPE_UNASSERT:
  477.           rsrc.QueryInterface(Ci.nsIRDFResource);
  478.           this._addOp(OP_DELETE, rsrc.ValueUTF8);
  479.           break;
  480.       }
  481.     } else {
  482.       var indexable = this._coop.get_from_resource(rsrc);
  483.       if (indexable && indexable.isIndexable) {
  484.         this._addOp(OP_ADD_FLOCK, indexable.id());
  485.       }
  486.     }
  487.   },
  488.  
  489.   // nsIRDFObserver
  490.   onAssert: function INDEXER_onAssert(ds, source, predicate, target) {
  491.     if (predicate.ValueUTF8 == PROP_NAME &&
  492.         ds.HasAssertion(this._resHistoryRoot, this._resHistoryChild,
  493.                         source, true)) {
  494.       var url = null;
  495.       try {
  496.         url = this._ios.newURI(source.ValueUTF8, null, null);
  497.       }
  498.       catch (e) { }
  499.       if (url && url.scheme == "http") {
  500.         this._addOp(OP_ADD_HISTORY, "history:" + url.spec);
  501.       }
  502.     }
  503.   },
  504.   
  505.   // nsIRDFObserver
  506.   onUnassert: function INDEXER_onUnassert(ds, source, predicate, target) {
  507.     if (source.ValueUTF8 == "NC:HistoryRoot" &&
  508.         predicate.ValueUTF8 == PROP_CHILD) {
  509.       target.QueryInterface(Ci.nsIRDFResource);
  510.       var url = null;
  511.       try {
  512.         url = this._ios.newURI(target.ValueUTF8, null, null);
  513.       } catch (e) {}
  514.       if (url && url.scheme == "http") {
  515.         this._addOp(OP_DELETE, "history:" + url.spec);
  516.       }
  517.     }
  518.   },
  519.   
  520.   // nsIRDFObserver
  521.   onChange: function INDEXER_onChange(ds, source, predicate, oldTarget, newTarget) {
  522.     if (predicate.ValueUTF8 == PROP_NAME &&
  523.         ds.HasAssertion(this._resHistoryRoot, this._resHistoryChild,
  524.                         source, true)) {
  525.       var url = null;
  526.       try {
  527.         url = this._ios.newURI(source.ValueUTF8, null, null);
  528.       } catch (e) {}
  529.       if (url && url.scheme == "http") {
  530.         this._addOp(OP_ADD_HISTORY, "history:" + url.spec);
  531.       }
  532.     }
  533.   },
  534.   
  535.   // nsIRDFObserver
  536.   onMove: function INDEXER_onMove(ds, oldSource, newSource, predicate, target) {
  537.   },
  538.   
  539.   // nsIRDFObserver
  540.   onBeginUpdateBatch: function INDEXER_onBeginUpdateBatch(ds) {
  541.   },
  542.   
  543.   // nsIRDFObserver
  544.   onEndUpdateBatch: function INDEXER_onEndUpdateBatch(ds) {
  545.   },
  546.  
  547.   // nsIObserver
  548.   observe: function INDEXER_observe(subject, topic, state) {
  549.     switch (topic) {
  550.       case "xpcom-shutdown":
  551.         var obs = Cc["@mozilla.org/observer-service;1"]
  552.           .getService(Ci.nsIObserverService);
  553.         obs.removeObserver(this, "xpcom-shutdown");
  554.         this._shutdown();
  555.         return;
  556.       case "nsPref:changed":
  557.         var prefService = Cc["@mozilla.org/preferences-service;1"]
  558.           .getService(Ci.nsIPrefBranch);
  559.         if (prefService.getPrefType("flock.service.indexer.enabled")) {
  560.           if (prefService.getBoolPref("flock.service.indexer.enabled")) {
  561.             this._enable();
  562.           } else {
  563.             this._disable();
  564.           }
  565.         } else {
  566.           this._enable();
  567.         }
  568.         if (prefService.getPrefType("flock.service.indexer.indexWebHistory")) {
  569.           if (prefService.getBoolPref("flock.service.indexer.indexWebHistory")) {
  570.             this._enableWebHistory();
  571.           } else {
  572.             this._disableWebHistory();
  573.           }
  574.         } else {
  575.           this._enableWebHistory();
  576.         }
  577.         break;
  578.     }
  579.   },
  580.   
  581.   // nsIClassInfo
  582.   getInterfaces: function INDEXER_getInterfaces(aCount) {
  583.     var interfaces = [Ci.flockIIndexer, Ci.nsIClassInfo, Ci.nsIObserver,
  584.                       Ci.flockIRDFObserver, Ci.nsIRDFObserver,
  585.                       Ci.nsITimerCallback, Ci.flockILuceneListener,
  586.                       Ci.flockIMigratable, Ci.nsIDOMEventListener];
  587.     aCount.value = interfaces.length;
  588.     return interfaces;
  589.   },
  590.  
  591.   // nsIClassInfo
  592.   getHelperForLanguage: function INDEXER_getHelperForLanguage(aLanguage) {
  593.     return null;
  594.   },
  595.  
  596.   // nsIClassInfo
  597.   contractID: CONTRACT_ID,
  598.  
  599.   // nsIClassInfo
  600.   classDescription: CLASS_NAME,
  601.  
  602.   // nsIClassInfo
  603.   classID: CLASS_ID,
  604.  
  605.   // nsIClassInfo
  606.   implementationLanguage: Ci.nsIProgrammingLanguage.JAVASCRIPT,
  607.  
  608.   // nsIClassInfo
  609.   flags: Ci.nsIClassInfo.SINGLETON,
  610.   
  611.   // nsISupports
  612.   QueryInterface: function INDEXER_QueryInterface(aIID) {
  613.     if (!aIID.equals(Ci.nsISupports) &&
  614.         !aIID.equals(Ci.flockIIndexer) &&
  615.         !aIID.equals(Ci.nsIClassInfo) &&
  616.         !aIID.equals(Ci.nsIObserver) &&
  617.         !aIID.equals(Ci.flockIRDFObserver) &&
  618.         !aIID.equals(Ci.nsIRDFObserver) &&
  619.         !aIID.equals(Ci.nsITimerCallback) &&
  620.         !aIID.equals(Ci.flockILuceneListener) &&
  621.         !aIID.equals(Ci.flockIMigratable) &&
  622.         !aIID.equals(Ci.nsIDOMEventListener))
  623.       throw Cr.NS_ERROR_NO_INTERFACE;
  624.     return this;
  625.   }
  626.  
  627. };
  628.  
  629. /******************************************************************************
  630.  * XPCOM Functions for construction and registration
  631.  ******************************************************************************/
  632. var Module = {
  633.   _firstTime: true,
  634.   registerSelf: function(aCompMgr, aFileSpec, aLocation, aType) {
  635.     if (this._firstTime) {
  636.       this._firstTime = false;
  637.       throw Cr.NS_ERROR_FACTORY_REGISTER_AGAIN;
  638.     }
  639.     aCompMgr = aCompMgr.QueryInterface(Ci.nsIComponentRegistrar);
  640.     aCompMgr.registerFactoryLocation(CLASS_ID, CLASS_NAME, CONTRACT_ID, aFileSpec, aLocation, aType);
  641.     
  642.     var catman = Cc["@mozilla.org/categorymanager;1"].getService(Ci.nsICategoryManager);
  643.     catman.addCategoryEntry("flockMigratable", CLASS_NAME, CONTRACT_ID, true, true);
  644.   },
  645.  
  646.   unregisterSelf: function(aCompMgr, aLocation, aType) {
  647.     aCompMgr = aCompMgr.QueryInterface(Ci.nsIComponentRegistrar);
  648.     aCompMgr.unregisterFactoryLocation(CLASS_ID, aLocation);        
  649.   },
  650.   
  651.   getClassObject: function(aCompMgr, aCID, aIID) {
  652.     if (!aIID.equals(Ci.nsIFactory))
  653.       throw Cr.NS_ERROR_NOT_IMPLEMENTED;
  654.     if (aCID.equals(CLASS_ID))
  655.       return Factory;
  656.     throw Cr.NS_ERROR_NO_INTERFACE;
  657.   },
  658.  
  659.   canUnload: function(aCompMgr) { return true; }
  660. };
  661.  
  662. var Factory = {
  663.   createInstance: function(aOuter, aIID)
  664.   {
  665.     if (aOuter != null)
  666.       throw Cr.NS_ERROR_NO_AGGREGATION;
  667.     return (new flockIndexer()).QueryInterface(aIID);
  668.   }
  669. };
  670.  
  671. function NSGetModule(aCompMgr, aFileSpec) { return Module; }
  672.  
  673.